﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using Comunication;
using VehicleAgent.TCPCommands;
using Timer = System.Timers.Timer;

namespace VehicleAgent
{               
    public partial class Vehicle : Form
    {
        #region Declarations

        private delegate void SetTextCallback(string text, Control textBox);
        private delegate void SetEnabledCallback(bool enabled, Control textBox);
        private Socket server;
        private ITcpPacketProcessor packetProcessor;
        private Timer notifyServerTimer;
        object timerLock = new object();
        object currentStatusLock = new object();
        private bool currentStatus;
        private decimal currentDistance;

        #endregion

        public Vehicle()
        {
            InitializeComponent();
        }
                

        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                packetProcessor = new PacketProcessor();
                ((PacketProcessor)packetProcessor).TakeVehicleResponseReceived += new PacketProcessor.BoolResponseEvent(Vehicle_TakeVehicleResponseReceived);
                ((PacketProcessor)packetProcessor).LowBalanceReceived += new PacketProcessor.Event(Vehicle_LowBalanceReceived);
                ((PacketProcessor)packetProcessor).OutOfCreditReceived += new PacketProcessor.Event(Vehicle_OutOfCreditReceived);
                ((PacketProcessor)packetProcessor).ConnectionEnded += new PacketProcessor.Event(Vehicle_ConnectionEnded);

                notifyServerTimer = new Timer(Properties.Settings.Default.InactiveNotifyServerInterval);
                notifyServerTimer.Elapsed += new System.Timers.ElapsedEventHandler(notifyServerTimer_Elapsed);

                server = TCPClient.ConnectToServer(Properties.Settings.Default.ServerPort, IPAddress.Parse(Properties.Settings.Default.ServerIP), packetProcessor, Properties.Settings.Default.TCPBytesToRead);


                btnStart.Enabled = false;
                btnStopNotify.Enabled = true;
                btnTakeVehicle.Enabled = true;
                txtClientId.Enabled = true;

                notifyServerTimer.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

        void Vehicle_ConnectionEnded()
        {
            lock (timerLock)
            {
                try
                {
                    notifyServerTimer.Stop();

                    SetEnabled(true, btnStart);
                    SetEnabled(false, btnLeaveVehicle);
                    SetEnabled(false, btnTakeVehicle);
                    SetEnabled(false, btnStopNotify);
                    SetEnabled(false, txtClientId);
                    MessageBox.Show(@"Comunication server lost connection",@"Error",MessageBoxButtons.OK,MessageBoxIcon.Warning);

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

        void Vehicle_OutOfCreditReceived()
        {
            lock (currentStatusLock)
            {
                currentStatus = false;
                currentDistance = 0;
                notifyServerTimer.Interval = Properties.Settings.Default.InactiveNotifyServerInterval;
                SetEnabled(true, btnTakeVehicle);
                SetEnabled(false, btnLeaveVehicle);
                SetEnabled(true, txtClientId);
            }
            MessageBox.Show("Saldo agotado");

        }

        private void SetText(string text, Control textBox)
        {

            if (textBox.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text, textBox });
            }
            else
            {
                textBox.Text = text;
            }
        }

        private void SetEnabled(bool enabled, Control control)
        {
            if (control.InvokeRequired)
            {
                SetEnabledCallback d = new SetEnabledCallback(SetEnabled);
                this.Invoke(d, new object[] { enabled, control });
            }
            else
            {
                control.Enabled = enabled;
            }
        }

        void Vehicle_LowBalanceReceived()
        {
            MessageBox.Show("Poco saldo disponible");
        }

        void notifyServerTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            lock (timerLock)
            {
                notifyServerTimer.Stop();
                lock (currentStatusLock)
                {
                    try
                    {
                        int clientId = 0;

                        if (currentStatus)
                        {
                            Random rnd = new Random();
                            currentDistance += new decimal(rnd.NextDouble());
                            clientId = int.Parse(txtClientId.Text);
                        }
                        else
                        {
                            currentDistance = 0;
                            clientId = 0;
                        }

                        TCPClient.SendCommand(server,
                                              new NotifyServerStatus(currentStatus, clientId,
                                                                     currentDistance));

                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
                notifyServerTimer.Start();
            }

        }

        void Vehicle_TakeVehicleResponseReceived(bool response)
        {
            lock (currentStatusLock)
            {
                try
                {
                    currentStatus = response;
                    if (currentStatus)
                    {
                        SetEnabled(true, btnLeaveVehicle);
                        SetEnabled(false, btnTakeVehicle);
                        SetEnabled(false, txtClientId);
                        int clientId = 0;

                        clientId = currentStatus ? int.Parse(txtClientId.Text) : 0;

                        TCPClient.SendCommand(server, new NotifyServerStatus(currentStatus, clientId, 0));
                        notifyServerTimer.Interval = Properties.Settings.Default.ActiveNotifyServerInterval;
                    }
                    else
                    {
                        MessageBox.Show(@"No esta habiltado para usar el vehiculo");
                        notifyServerTimer.Interval = Properties.Settings.Default.InactiveNotifyServerInterval;
                    }
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

        private void btnTakeVehicle_Click(object sender, EventArgs e)
        {
            try
            {
                int clientId;
                errorProvider.SetError(txtClientId, string.Empty);

                if (!int.TryParse(txtClientId.Text, out clientId))
                {
                    errorProvider.SetError(txtClientId, "El identificador del cliente debe ser un numero entero");
                }
                else
                {
                    TCPClient.SendCommand(server, new TakeVehicle(int.Parse(txtClientId.Text)));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnLeaveVehicle_Click(object sender, EventArgs e)
        {
            lock (currentStatusLock)
            {
                try
                {
                    Random rnd = new Random();
                    TCPClient.SendCommand(server,
                                          new LeaveVehicle(int.Parse(txtClientId.Text), new decimal(rnd.NextDouble())));
                    currentStatus = false;
                    currentDistance = 0;
                    notifyServerTimer.Interval = Properties.Settings.Default.InactiveNotifyServerInterval;
                    btnTakeVehicle.Enabled = true;
                    btnLeaveVehicle.Enabled = false;
                    txtClientId.Enabled = true;
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            try
            {
                TCPClient.Close(server);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

    }
}
